home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Practical Algorithms for Image Analysis
/
Practical Algorithms for Image Analysis.iso
/
TARFILE.GZ
/
tarfile
/
ch_7.2
/
fltrfreq
/
fltrfreq.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-09-11
|
13KB
|
381 lines
/*
* fltrfreq.c
*
* Practical Algorithms for Image Analysis
*
* Copyright (c) 1997, 1998, 1999 MLMSoftwareGroup, LLC
*/
/* FLTRFREQ: program performs lowpass, highpass, bandpass, or bandstop
* filtering on image by applying filter in frequency domain
* usage: fltrfreq inimg outimg [-l f1] [-h f1] [-b f1 f2]
* [-s f1 f2] [-n ORDER] [-g] [-p] [-I] [-L]
* Note: Low/High-pass frequencies are specified as fraction of 1,
* where 1 is normalized highest frequency.
* Note: image sidelength must be power of 2; if not the case,
* this program changes the size to be so, either the
* next higher or lower power of 2 as user-chosen (<-p>).
*
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include "ip.h"
#if defined(WIN32) || defined(LINUX)
#define M_PI 3.14159265358979323846
#define log2(a) (log(a)/ 0.6931471805599)
#define exp2(a) (pow((double)2, (double)a))
#endif
#define PASS_TYPE_DFLT 0 /* default filter passband is low-pass */
#define F1_DFLT 0.5 /* default filter cutoff is half */
#define F2_DFLT 0.0
#define ORDER_DFLT 1 /* default order of Butterworth filter */
#define BUTTERWORTH 1 /* Butterworth filter type */
#define GAUSSIAN 2 /* Gaussian filter type */
void input (int argc, char *argv[], short *passType, double *f1, double *f2, double *order, short *fltrType, short *zeroPad, long *invertFlag);
void window (float **image, long nRow, long nCol, long nRowS, long nColS);
void usage (short flag);
main (argc, argv)
int argc;
char *argv[];
{
register long x, y, nCol, nRow, /* image input sidelengths */
nCol2, nRow2; /* power of 2 spectrum sidelengths */
// nColD2, nRowD2; /* middle row/column of spectrum image */
long xStart, yStart; /* beginning coord.s of pow spec in image */
Image *imgI, *imgO; /* I/O image structures */
unsigned char **imgIn, /* image array */
**imgOut; /* output image */
short passType; /* lowpass=0, high=1, band=2, stop=3 */
double f1, f2; /* 3dB frequency bounds of filter */
double order; /* order of Butterworth filter */
short fltrType; /* Butterworth or Gaussian filter type */
short zeroPad; /* if 1, upsize image to pow of 2; 0 => down */
float **imgReal, **imgImag; /* complex image arrays */
//float *wndwX, *wndwY; /* row and column window vectors */
double min, max; /* maximum value in power spectrum */
float max0, min0; /* initial max,min values of image */
double norm; /* normalization factor for img intensities */
double temp;
long invertFlag;
//double sqrt (), log2 (), log10 (), exp2 ();
input (argc, argv, &passType, &f1, &f2, &order, &fltrType, &zeroPad, &invertFlag);
/* read input image */
imgI = ImageIn (argv[1]);
imgIn = imgI->img;
nRow = ImageGetHeight (imgI);
nCol = ImageGetWidth (imgI);
printf ("Original image is %3dx%3d.\n", nCol, nRow);
/* invert image intensities for going into processing */
if (invertFlag) {
for (y = 0; y < nRow; y++)
for (x = 0; x < nCol; x++)
imgIn[y][x] = 255 - imgIn[y][x];
}
/* check for image sidelengths powers of 2 */
nRow2 = nRow;
temp = log2 ((double) nRow);
if ((temp - (long) temp) != 0.0)
nRow2 = (zeroPad == 0) ?
(long) exp2 ((double) ((long) temp)) : (long) exp2 ((double) ((long) temp + 1));
nCol2 = nCol;
temp = log2 ((double) nCol);
if ((temp - (long) temp) != 0.0)
nCol2 = (zeroPad == 0) ?
(long) exp2 ((double) ((long) temp)) : (long) exp2 ((double) ((long) temp + 1));
if (nRow2 != nRow || nCol2 != nCol)
printf ("Image size changed to %dx%d so power of 2 (required for FFT).\n",
nRow2, nCol2);
/* allocate output image */
imgO = ImageAlloc (nRow2, nCol2, ImageGetDepth (imgI));
imgOut = ImageGetPtr (imgO);
/* allocate memory for complex array */
if ((imgReal = (float **) calloc (nRow2, sizeof (float *))) == NULL)
exit (2);
for (y = 0; y < nRow2; y++)
if ((imgReal[y] = (float *) calloc (nCol2, sizeof (float))) == NULL)
exit (3);
if ((imgImag = (float **) calloc (nRow2, sizeof (float *))) == NULL)
exit (4);
for (y = 0; y < nRow2; y++)
if ((imgImag[y] = (float *) calloc (nCol2, sizeof (float))) == NULL)
exit (5);
/* center the image, and zero-pad or reduce size if required */
printf ("Forward 2-D FFT being performed.\n");
if (zeroPad == 0) {
yStart = (nRow - nRow2) / 2;
xStart = (nCol - nCol2) / 2;
for (y = 0, max0 = (float) 0.0, min0 = (float) 256.0; y < nRow2; y++) {
for (x = 0; x < nCol2; x++) {
imgReal[y][x] = (float) imgIn[y + yStart][x + xStart];
imgImag[y][x] = (float) 0.0;
if (imgReal[y][x] > max0)
max0 = imgReal[y][x];
if (imgReal[y][x] < min0)
min0 = imgReal[y][x];
}
}
}
else {
yStart = (nRow2 - nRow) / 2;
xStart = (nCol2 - nCol) / 2;
for (y = 0; y < nRow; y++) {
for (x = 0; x < nCol; x++) {
imgReal[y + yStart][x + xStart] = (float) imgIn[y][x];
imgImag[y][x] = (float) 0.0;
}
}
}
/* perform windowing */
if (zeroPad == 0)
window (imgReal, nRow2, nCol2, nRow2, nCol2);
else
window (imgReal, nRow2, nCol2, nRow, nCol);
/* perform 2-dimensional FFT */
fft2d (imgReal, imgImag, nRow2, nCol2, -1);
/* perform filtering on frequency-domain image */
printf ("Frequency-domain filtering being performed.\n");
if (fltrType == BUTTERWORTH)
fltrbttr (imgReal, imgImag, nRow2, nCol2, passType, f1, f2, order);
else
fltrgaus (imgReal, imgImag, nRow2, nCol2, passType, f1, f2);
/* perform inverse FFT */
printf ("Inverse 2-D FFT being performed.\n");
fft2d (imgReal, imgImag, nRow2, nCol2, 1);
/* find post-processing normalization factors for image */
for (y = 0, min = 1000.0, max = -1000.0; y < nRow2; y++) {
for (x = 0; x < nCol2; x++) {
if (imgReal[y][x] < min)
min = imgReal[y][x];
if (imgReal[y][x] > max)
max = imgReal[y][x];
}
}
if (min > 0.0)
min = 0.0;
norm = max0 / (max - min);
for (y = 0; y < nRow2; y++)
for (x = 0; x < nCol2; x++)
imgOut[y][x] = (unsigned char) ((imgReal[y][x] - min) * norm + 0.5);
/* output image - un-invert it */
if (invertFlag) {
for (y = 0; y < nRow2; y++)
for (x = 0; x < nCol2; x++)
imgOut[y][x] = 255 - imgOut[y][x];
}
/* write output image */
ImageOut (argv[2], imgO);
return (0);
}
/* WINDOW: function multiplies vector by smoothing window
* usage: window (image, nRow, nCol, nRowS, nColS)
* Note: There are 2 sets of image sizes for the following
* reason. The (nRow, nCol) size is the image size to be
* windowed; that is, this is a power of 2 for the FFT.
* The (nRowS, nColS) size is a smaller size that is the original
* image size before zero-padding. This smaller image has
* been placed in the middle of the zero-padded image. It is
* the SMALLER IMAGE, NOT THE FINAL IMAGE that should be windowed.
*/
void
window (image, nRow, nCol, nRowS, nColS)
float **image; /* image to be smoothed */
long nRow, nCol; /* size of image to be windowed */
long nRowS, nColS; /* size of smaller image b4 padding */
{
float *hammingX, *hammingY; /* horiz. and vert. hamming windows */
double nM1; /* no. rows/cols minus 1 */
long xStart, yStart; /* offset smaller image in larger */
long x, y;
/* allocate space for hamming windows */
if ((hammingX = (float *) calloc (nCol, sizeof (*hammingX))) == NULL)
exit (1);
if ((hammingY = (float *) calloc (nRow, sizeof (*hammingY))) == NULL)
exit (2);
/* put window in middle of zeroed vector if image has been padded */
for (x = 0; x < nCol; x++)
hammingX[x] = (float) 0.0;
for (y = 0; y < nRow; y++)
hammingY[y] = (float) 0.0;
xStart = (nCol - nColS) / 2;
yStart = (nRow - nRowS) / 2;
/* calculate Hamming window */
nM1 = (double) (nColS - 1);
for (x = 0; x < nColS; x++)
hammingX[x + xStart] = (float) (0.54 - 0.46 * cos ((M_PI * 2.0 * (double) x) / nM1));
nM1 = (double) (nRowS - 1);
for (y = 0; y < nRowS; y++)
hammingY[y + yStart] = (float) (0.54 - 0.46 * cos ((M_PI * 2.0 * (double) y) / nM1));
/* apply window to image */
for (y = 0; y < nRow; y++)
for (x = 0; x < nCol; x++)
image[y][x] = image[y][x] * hammingX[x] * hammingY[y];
}
/* USAGE: function gives instructions on usage of program
* usage: usage (flag)
* When flag is 1, the long message is given, 0 gives short.
*/
void
usage (flag)
short flag; /* flag =1 for long message; =0 for short message */
{
/* print short usage message or long */
printf ("USAGE: fltrfreq inimg outimg [-l f1] [-h f1] [-b f1 f2] \n");
printf (" [-s f1 f2] [-n ORDER] [-g] [-p] [-I] [-L]\n");
if (flag == 0)
exit (1);
printf ("\nfltrfreq performs frequency domain filtering on image.\n\n");
printf ("ARGUMENTS:\n");
printf (" inimg: input image filename (TIF)\n");
printf (" outimg: output image filename (TIF)\n\n");
printf ("OPTIONS:\n");
printf (" -l f1: LOW-PASS FILTER passing frequencies below cutoff, f1.\n");
printf (" -h f1: HIGH-PASS FILTER passing frequencies above cutoff, f1.\n");
printf (" -b f1 f2: BAND-PASS FILTER passing frequencies between f1-f2.\n");
printf (" -s f1 f2: STOP-BAND-PASS FILTER passing frequencies not f1-f2.\n");
printf (" -n ORDER: order of Butterworth filter, dflt = %d.\n", ORDER_DFLT);
printf (" -g: flag to perform Gaussian filter, default is Butterworth.\n");
printf (" -p: flag for zero padding if set, and image row or column is\n");
printf (" not a power of 2, image size is increased by zero-.\n");
printf (" padding; otherwise image size is decreased (default).\n\n");
printf (" NOTE -- The frequencies (f1,f2) should be expressed as a\n");
printf (" number 0 to 1.0; this is a fractional frequency value of the\n");
printf (" full original pass band. For example, a low-pass filter with\n");
printf (" cutoff frequency of 0.5 will reduce the bandwidth by half.\n");
printf (" Where the image is not square, the fractional frequency\n");
printf (" value is relative to the higher frequency corresponding to\n");
printf (" the longer x or y axis.\n");
printf (" -I: invert image before processing\n");
printf (" -L: print Software License for this module\n");
exit (1);
}
/* INPUT: function reads input parameters
* usage: input (argc, argv, &passType, &f1, &f2,
* &order, &fltrType, &zeroPad)
*/
void
input (argc, argv, passType, f1, f2, order, fltrType, zeroPad, invertFlag)
int argc;
char *argv[];
short *passType; /* lowpass=0, highpass=1, bandpass=2, stoppass= 3 */
double *f1, *f2; /* 3db cutoff frequencies */
double *order; /* order of Butterworth filter */
short *fltrType; /* filter type */
short *zeroPad; /* if 1, increase img size to 2-power; 0 => decrease */
long *invertFlag; /* invert image before processing */
{
long n;
double atof ();
if (argc < 3)
usage (1);
*passType = PASS_TYPE_DFLT;
*f1 = F1_DFLT;
*f2 = F2_DFLT;
*order = ORDER_DFLT;
*fltrType = BUTTERWORTH;
*zeroPad = 0;
*invertFlag = 0;
for (n = 3; n < argc; n++) {
if (strcmp (argv[n], "-l") == 0) {
if (++n == argc || argv[n][0] == '-')
usage (0);
*passType = 0;
*f1 = atof (argv[n]);
}
else if (strcmp (argv[n], "-h") == 0) {
if (++n == argc || argv[n][0] == '-')
usage (0);
*passType = 1;
*f1 = atof (argv[n]);
}
else if (strcmp (argv[n], "-b") == 0) {
if (++n == argc || argv[n][0] == '-')
usage (0);
*passType = 2;
*f1 = atof (argv[n]);
if (++n == argc || argv[n][0] == '-')
usage (0);
*f2 = atof (argv[n]);
}
else if (strcmp (argv[n], "-s") == 0) {
if (++n == argc || argv[n][0] == '-')
usage (0);
*passType = 3;
*f1 = atof (argv[n]);
if (++n == argc || argv[n][0] == '-')
usage (0);
*f2 = atof (argv[n]);
}
else if (strcmp (argv[n], "-n") == 0) {
if (++n == argc || argv[n][0] == '-')
usage (0);
*order = atof (argv[n]);
}
else if (strcmp (argv[n], "-g") == 0)
*fltrType = GAUSSIAN;
else if (strcmp (argv[n], "-p") == 0)
*zeroPad = 1;
else if (strcmp (argv[n], "-I") == 0)
*invertFlag = 1;
else if (strcmp (argv[n], "-L") == 0) {
print_sos_lic ();
exit (0);
}
else
usage (0);
}
if (*f1 < 0.0 || *f1 >= 1.0 || *f2 < 0.0 || *f2 >= 1.0) {
printf ("Cutoff frequency values must be between 0.0 and 1.0.\n");
usage (1);
}
return;
}